package com.cneport.transfer.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;

import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;

/**
 * Copyright (c) 2012, 东方口岸科技有限公司 XML文件序列化
 * @author wudi
 * @version 1.0
 * @since 2012-1-12
 */
public class XmlSerializer {

    /**
     * 序列化
     * @param obj
     *            实体参数
     * @return String 序列化后的字符串
     * @throws Exception
     *             抛出异常
     */
    public static String serialize(Object obj) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(obj.getClass());
        Marshaller marshaller = jc.createMarshaller();
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        marshaller.marshal(obj, stream);
        return new String(stream.toByteArray(), "UTF-8");
    }

    /**
     * 序列化成实体
     * @param obj
     *            实体参数
     * @return Element 返回序列化后的实体
     * @throws Exception
     *             抛出异常
     */
    public static Element serializeToElement(Object obj) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(obj.getClass());
        Marshaller marshaller = jc.createMarshaller();
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.newDocument();
        marshaller.marshal(obj, doc);
        return doc.getDocumentElement();
    }

    /**
     * 反序列化
     * @param str
     *            字符串
     * @param clazz
     *            模板类
     * @return Object
     * @throws Exception
     *             抛出异常
     */
    public static Object deSerialize(String str, Class<?> clazz)
            throws Exception {
        return deSerialize(str, clazz, "UTF-8");
    }

    /**
     * 反序列化的具体操作
     * @param str
     *            字符串
     * @param clazz
     *            模板类
     * @param encoding
     *            编码格式
     * @return Object
     * @throws Exception
     *             抛出异常
     */
    public static Object deSerialize(String str, Class<?> clazz, String encoding)
            throws Exception {
        JAXBContext jc = JAXBContext.newInstance(clazz);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        byte[] bytes = str.getBytes(encoding);
        ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
        return unmarshaller.unmarshal(stream);
    }

    /**
     * 反序列化到实体
     * @param str
     *            字符串
     * @param encoding
     *            编码格式
     * @return Element
     * @throws Exception
     *             抛出异常
     */
    public static Element deSerializeToElement(String str, String encoding)
            throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        byte[] bytes = str.getBytes(encoding);
        ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
        Document doc = db.parse(stream);
        return doc.getDocumentElement();
    }

    /**
     * 反序列化
     * @param element
     *            实体参数
     * @return String
     * @throws Exception
     *             抛出异常
     */
    public static String deSerialize(Element element) throws Exception {
        TransformerFactory tfc = TransformerFactory.newInstance();
        Transformer tf = tfc.newTransformer();
        // tf.setOutputProperty("encoding", "UTF-8");
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        tf.transform(new DOMSource(element), new StreamResult(bos));
        String result = bos.toString("UTF-8");
        bos.close();
        return result;
    }

    /**
     * 获取文件
     * @param clazz
     *            模板类
     * @param path
     *            文件路径
     * @return Object
     * @throws Exception
     *             抛出异常
     */
    public static Object getFile(Class<?> clazz, String path) throws Exception {
        InputStream is = new FileInputStream(path);
        JAXBContext jc = JAXBContext.newInstance(clazz);
        Unmarshaller u = jc.createUnmarshaller();
        return u.unmarshal(is);
    }

    /**
     * XML格式化
     * @param xml
     *            字符串
     * @return String
     * @throws Exception
     *             抛出异常
     */
    public static String formatXML(String xml) throws Exception {
        Document document = parseXmlFile(xml);
        OutputFormat format = new OutputFormat(document);
        format.setLineWidth(65);
        format.setIndent(2);
        Writer out = new StringWriter();
        XMLSerializer s = new XMLSerializer(out, format);
        s.serialize(document);
        return out.toString();
    }

    /**
     * 生成xml文件
     * @param in
     *            xml字符串
     * @return Document
     * @throws Exception
     *             抛出异常
     */
    private static Document parseXmlFile(String in) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = dbf.newDocumentBuilder();
        InputSource is = new InputSource(new StringReader(in));
        return builder.parse(is);
    }

    public static byte[] convert2Xml(Object dataObject) throws Exception {
        byte[] xml = null;
        JAXBContext jc = JAXBContext.newInstance(dataObject.getClass());
        Marshaller marshaller = jc.createMarshaller();
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        ByteArrayOutputStream byteArrayOutputStream = null;
        byteArrayOutputStream = new ByteArrayOutputStream();
        marshaller.marshal(dataObject, byteArrayOutputStream);
        xml = byteArrayOutputStream.toByteArray();
        return xml;
    }
}
